﻿using System;
using System.Collections.Specialized;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Utilities.Tests
{
    [TestClass()]
    public class ReflectiveModelBinderTest
    {
        private TestContext testContextInstance;

        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion

        class TestBindingObject
        {
            // strings
            public string NonEmptyStringProperty { get; set; }
            public string EmptyStringProperty { get; set; }

            // enumerations
            public enum TestEnum
            {
                EnumItem0 = 0,
                EnumItem1 = 1,
                EnumItem2 = 2
            }

            public TestEnum DefaultEnumProperty { get; set; }
            public TestEnum EnumProperty1 { get; set; }
            public TestEnum EnumProperty2ByName { get; set; }

            // date time
            public DateTime DefaultDateTime { get; set; }
            public DateTime NonDefaultDateTime { get; set; }

            // Nullable date time
            public DateTime? NullDateTime { get; set; }
            public DateTime? NonNullDateTime { get; set; }

            // bool
            public bool DefaultBoolean { get; set; }
            public bool NonDefaultBoolean { get; set; }
        };

        class TestSubscriber : IPropertyChangedSubscriber
        {
            public bool HasChanged { get; private set; }
            public void OnPropertyChanged(object o, string propertyName, object oldValue, object newValue)
            {
                HasChanged = true;
            }
        }

        [TestMethod()]
        public void ReflectiveModelBinderBindTest()
        {
            TestBindingObject model = new TestBindingObject();

            NameValueCollection collection = new NameValueCollection();

            // strings
            collection.Add("NonEmptyStringProperty", "TestString");
            collection.Add("EmptyStringProperty", string.Empty);

            // enumerations
            collection.Add("DefaultEnumProperty", null);
            collection.Add("EnumProperty1", "1");
            collection.Add("EnumProperty2ByName", "EnumItem2");

            // date time
            DateTime testDateTime = new DateTime(2002, 5, 25);
            collection.Add("DefaultDateTime", null);
            collection.Add("NonDefaultDateTime", testDateTime.ToString());

            // Nullable date time
            collection.Add("NullDateTime", null);
            collection.Add("NonNullDateTime", testDateTime.ToString());

            // bool
            collection.Add("DefaultBoolean", null);
            collection.Add("NonDefaultBoolean", "True"); // "true" should be good too

            TestSubscriber subscriber = new TestSubscriber();

            ReflectiveModelBinder.Bind(model, collection, subscriber);

            // strings
            Assert.AreEqual("TestString", model.NonEmptyStringProperty);
            Assert.AreEqual(string.Empty, model.EmptyStringProperty);

            // enumerations
            Assert.AreEqual(TestBindingObject.TestEnum.EnumItem0, model.DefaultEnumProperty);
            Assert.AreEqual(TestBindingObject.TestEnum.EnumItem1, model.EnumProperty1);
            Assert.AreEqual(TestBindingObject.TestEnum.EnumItem2, model.EnumProperty2ByName);

            // date time
            Assert.AreEqual(DateTime.MinValue, model.DefaultDateTime);
            Assert.AreEqual(testDateTime, model.NonDefaultDateTime);

            // Nullable date time
            Assert.AreEqual(null, model.NullDateTime);
            Assert.AreEqual(testDateTime, model.NonNullDateTime);

            // bool
            Assert.AreEqual(false, model.DefaultBoolean);
            Assert.AreEqual(true, model.NonDefaultBoolean);

            Assert.IsTrue(subscriber.HasChanged);
        }
    }
}
